package com.hjy.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.hjy.mapper.SysAclMapper;
import com.hjy.mapper.SysRoleAclMapper;
import com.hjy.mapper.SysRoleUserMapper;
import com.hjy.pojo.*;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class SysCoreService {

    @Resource
    private SysAclMapper sysAclMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private SysRoleAclMapper sysRoleAclMapper;


    public List<SysAcl> getCurrentUserAclList(HttpServletRequest request) {
        int userId = ((SysUser)request.getSession().getAttribute("user")).getId();
        return getUserAclList(userId,request);
    }

    public List<SysAcl> getRoleAclList(int roleId) {
        QueryWrapper<SysRoleAcl> wrapper =new  QueryWrapper<>();
        wrapper.in("role_id",Lists.<Integer>newArrayList(roleId));
        List<Integer> aclIdList =  sysRoleAclMapper.selectList(wrapper).stream().map(sysRoleAcl -> sysRoleAcl.getAclId()).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(aclIdList)) {
            return Lists.newArrayList();
        }

        return sysAclMapper.selectBatchIds(aclIdList);
    }

    public List<SysAcl> getUserAclList(int userId,HttpServletRequest request) {
        if (isSuperAdmin(request)) {
            return sysAclMapper.selectList(null);
        }

        QueryWrapper<SysRoleUser> wrapper1 =new  QueryWrapper<>();
        wrapper1.eq("user_id",userId);
        List<Integer> userRoleIdList =  sysRoleUserMapper.selectList(wrapper1).stream().map(sysRoleUser -> sysRoleUser.getRoleId()).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(userRoleIdList)) {
            return Lists.newArrayList();
        }

        QueryWrapper<SysRoleAcl> wrapper =new  QueryWrapper<>();
        wrapper.in("role_id",userRoleIdList);
        List<Integer> userAclIdList =  sysRoleAclMapper.selectList(wrapper).stream().map(sysRoleAcl -> sysRoleAcl.getAclId()).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(userAclIdList)) {
            return Lists.newArrayList();
        }

        return sysAclMapper.selectBatchIds(userAclIdList);
    }

    public boolean isSuperAdmin(HttpServletRequest request) {
        // 这里是我自己定义了一个假的超级管理员规则，实际中要根据项目进行修改
        // 可以是配置文件获取，可以指定某个用户，也可以指定某个角色
        SysUser sysUser = (SysUser)request.getSession().getAttribute("user");
        if (sysUser.getMail().contains("admin")) {
//            return true;
        }
        return false;
    }

    public boolean hasUrlAcl(String url,HttpServletRequest request) {
        if (isSuperAdmin(request)) {
            return true;
        }
        QueryWrapper<SysAcl> wrapper = new QueryWrapper<>();
        wrapper.eq("url",url);
        List<SysAcl> aclList = sysAclMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(aclList)) {
            return true;
        }

        List<SysAcl> userAclList = getCurrentUserAclListFromCache(request);
        Set<Integer> userAclIdSet = userAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        boolean hasValidAcl = false;
        // 规则：只要有一个权限点有权限，那么我们就认为有访问权限
        for (SysAcl acl : aclList) {
            // 判断一个用户是否具有某个权限点的访问权限
            if (acl == null || acl.getStatus() != 1) { // 权限点无效
                continue;
            }
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                return true;
            }
        }
        if (!hasValidAcl) {
            return true;
        }
        return false;
    }

    @Cacheable(value = "sysUser :: getCurrentUserAclListFromCache",key = "#p0")
    public List<SysAcl> getCurrentUserAclListFromCache(HttpServletRequest request) {
        int userId = ((SysUser)request.getSession().getAttribute("user")).getId();
        return getUserAclList(userId,request);
    }
}
